<!DOCTYPE html>



  


<html class="theme-next muse use-motion" lang="zh-Hans">
<head><meta name="generator" content="Hexo 3.8.0">
  <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="theme-color" content="#222">









<meta http-equiv="Cache-Control" content="no-transform">
<meta http-equiv="Cache-Control" content="no-siteapp">
















  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css">







<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css">

<link href="/css/main.css?v=5.1.4" rel="stylesheet" type="text/css">


  <link rel="apple-touch-icon" sizes="180x180" href="/images/apple-touch-icon-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="32x32" href="/images/favicon-32x32-next.png?v=5.1.4">


  <link rel="icon" type="image/png" sizes="16x16" href="/images/favicon-16x16-next.png?v=5.1.4">


  <link rel="mask-icon" href="/images/logo.svg?v=5.1.4" color="#222">





  <meta name="keywords" content="Hexo, NexT">





  <link rel="alternate" href="/atom.xml" title="renhao" type="application/atom+xml">






<meta name="description" content="本文为Tasks,microtasks,queues and schedules的译文。">
<meta property="og:type" content="article">
<meta property="og:title" content="【译】js中的宏任务、微任务">
<meta property="og:url" content="https://huangrenhao.gitee.io/2019/11/06/js-tasks-microtasks/index.html">
<meta property="og:site_name" content="renhao">
<meta property="og:description" content="本文为Tasks,microtasks,queues and schedules的译文。">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="https://huangrenhao.gitee.io/2019/11/06/js-tasks-microtasks/ex-1.png">
<meta property="og:image" content="https://huangrenhao.gitee.io/2019/11/06/js-tasks-microtasks/ex-2.png">
<meta property="og:updated_time" content="2020-09-03T08:50:37.000Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="【译】js中的宏任务、微任务">
<meta name="twitter:description" content="本文为Tasks,microtasks,queues and schedules的译文。">
<meta name="twitter:image" content="https://huangrenhao.gitee.io/2019/11/06/js-tasks-microtasks/ex-1.png">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Muse',
    version: '5.1.4',
    sidebar: {"position":"left","display":"post","offset":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: {"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="https://huangrenhao.gitee.io/2019/11/06/js-tasks-microtasks/">





  <title>【译】js中的宏任务、微任务 | renhao</title>
  








<link rel="stylesheet" href="/css/prism-tomorrow.css" type="text/css"></head>

<body itemscope="" itemtype="http://schema.org/WebPage" lang="zh-Hans">
  
  
    
  

  <div class="container sidebar-position-left page-post-detail">
    <div class="headband"></div>

    <header id="header" class="header" itemscope="" itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/" class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">renhao</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle"></p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br>
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br>
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br>
            
            归档
          </a>
        </li>
      

      
    </ul>
  

  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope="" itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="https://huangrenhao.gitee.io/2019/11/06/js-tasks-microtasks/">

    <span hidden itemprop="author" itemscope="" itemtype="http://schema.org/Person">
      <meta itemprop="name" content="renhao">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope="" itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="renhao">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">【译】js中的宏任务、微任务</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2019-11-06T11:28:59+08:00">
                2019-11-06
              </time>
            

            

            
          </span>

          
            <span class="post-category">
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope="" itemtype="http://schema.org/Thing">
                  <a href="/categories/js/" itemprop="url" rel="index">
                    <span itemprop="name">js</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
              <span class="post-comments-count">
                <span class="post-meta-divider">|</span>
                <span class="post-meta-item-icon">
                  <i class="fa fa-comment-o"></i>
                </span>
                <a href="/2019/11/06/js-tasks-microtasks/#comments" itemprop="discussionUrl">
                  <span class="post-comments-count valine-comment-count" data-xid="/2019/11/06/js-tasks-microtasks/" itemprop="commentCount"></span>
                </a>
              </span>
            
          

          
          

          

          
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">字数统计&#58;</span>
                
                <span title="字数统计">
                  2.1k
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">阅读时长 &asymp;</span>
                
                <span title="阅读时长">
                  8
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p>本文为<a href="https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/?utm_source=html5weekly" target="_blank" rel="noopener">Tasks,microtasks,queues and schedules</a>的译文。<a id="more"></a></p>
<h2 id="一个简单实例"><a href="#一个简单实例" class="headerlink" title="一个简单实例"></a>一个简单实例</h2><pre><code>console.log(&#39;script start&#39;);

setTimeout(function() {
  console.log(&#39;setTimeout&#39;);
}, 0);

Promise.resolve().then(function() {
  console.log(&#39;promise1&#39;);
}).then(function() {
  console.log(&#39;promise2&#39;);
});

console.log(&#39;script end&#39;);
</code></pre><p>正确答案应该是<code>script start</code>, <code>script end</code>, <code>promise1</code>, <code>promise2</code>, <code>setTimeout</code>，但是会由于浏览器的不同结果也不同。在Microsoft Edge, Firefox 40, iOS Safari 和 desktop Safari 8.0.8会在<code>promise1,promise2</code>之前打印<code>setTimeout</code>，在Firefox 39 和 Safari 8.0.7 表现正确。</p>
<h2 id="深层原因"><a href="#深层原因" class="headerlink" title="深层原因"></a>深层原因</h2><p>每个线程都会有它自己的event loop(事件循环)，所以都能独立运行。然而所有同源窗口会共享一个event loop以同步通信。event loop会一直运行，来执行进入队列的宏任务。一个event loop有多种的宏任务源，这些宏任务源保证了在本任务源内的顺序。但是浏览器每次都会选择一个源中的一个宏任务去执行。这保证了浏览器给与一些宏任务（如用户输入）以更高的优先级。</p>
<h3 id="宏任务（task）"><a href="#宏任务（task）" class="headerlink" title="宏任务（task）"></a>宏任务（task）</h3><p>浏览器为了能够使得JS内部task与DOM任务能够有序的执行，会在一个task执行结束后，在下一个 task 执行开始前，对页面进行重新渲染 （task-&gt;渲染-&gt;task-&gt;…）<br>鼠标点击会触发一个事件回调，需要执行一个宏任务，然后解析HTMl。还有上面例子中setTimeout的作用是等待给定的时间后为它的回调产生一个新的宏任务。这就是为什么打印<code>setTimeout</code>在<code>script end</code>之后。因为打印<code>script end</code>是第一个宏任务里面的事情，而<code>setTimeout</code>是另一个独立的任务里面打印的。</p>
<h3 id="微任务（Microtasks）"><a href="#微任务（Microtasks）" class="headerlink" title="微任务（Microtasks）"></a>微任务（Microtasks）</h3><p>微任务通常来说就是需要在当前 task 执行结束后立即执行的任务，比如对一系列动作做出反馈，或者是需要异步的执行任务而又不需要分配一个新的 task，这样便可以减小一点性能的开销。只要执行栈中没有其他的js代码正在执行且每个宏任务执行完，微任务队列会立即执行。如果在微任务执行期间微任务队列加入了新的微任务，会将新的微任务加入队列尾部，之后也会被执行。微任务包括了mutation observe的回调还有上面的例子中promise的回调。</p>
<p>一旦一个pormise有了结果，或者早已有了结果（有了结果是指这个promise到了fulfilled或rejected状态），它就会为它的回调产生一个微任务，这就保证了回调异步的执行即使这个promise早已有了结果。所以对一个已经有了结果的promise调用<code>.then(yey, nay)</code>会立即产生一个微任务。这就是为什么<code>promise1,promise2</code>会打印在<code>script end</code>之后，因为所有微任务执行的时候，当前执行栈的代码必须已经执行完毕。<code>promise1,promise2</code>会打印在<code>setTimeout</code>之前是因为所有微任务总会在下一个宏任务之前全部执行完毕。</p>
<h3 id="不同浏览器打印顺序不一致原因"><a href="#不同浏览器打印顺序不一致原因" class="headerlink" title="不同浏览器打印顺序不一致原因"></a>不同浏览器打印顺序不一致原因</h3><p>有些浏览器会打印出：<code>script start, script end, setTimeout, promise1, promise2</code>。他们会在setTimeout之后执行promise的回调，就好像这些浏览器会把promise的回调视作一个新的宏任务而不是微任务。</p>
<p>其实无可厚非，因为promises 来自于ECMAScript 的标准而不是HTML标准。ECMAScript 有个关于jobs的概念和微任务挺类似的，但是否明确具有关联关系却尚未定论<a href="https://esdiscuss.org/topic/the-initialization-steps-for-web-browsers#content-16" target="_blank" rel="noopener">（相关讨论）</a>。然而，普遍的观点是promise应该属于微任务。</p>
<p>如果说把 promise 当做一个新的 task 来执行的话，这将会造成一些性能上的问题，因为 promise 的回调函数可能会被延迟执行，因为在每一个 task 执行结束后浏览器可能会进行一些渲染工作。由于作为一个 task 将会和其他任务来源（task source）相互影响，这也会造成一些不确定性，同时这也将打破一些与其他 API 的交互，这样一来便会造成一系列的问题。</p>
<p>这里有一个关于让Edge把promise加入微任务的提议，其实WebKit 早已悄悄正确实现。所以我猜Safari最终会修复，Firefox 43好像已修复。</p>
<blockquote>
<p>promise 为什么是微任务：promise 在浏览器里一般使用 mutationObserver，在 node 中使用 process.nextTick。可以参考 <a href="https://github.com/stefanpenner/es6-promise" target="_blank" rel="noopener">pormise 实现</a>（尽量满足规范）</p>
</blockquote>
<h3 id="分辨宏任务、微任务"><a href="#分辨宏任务、微任务" class="headerlink" title="分辨宏任务、微任务"></a>分辨宏任务、微任务</h3><p>实际测试是一种方法，观察日志打印顺序与promise和setTimeout的关系，但是首先浏览器对这两者的实现要正确。<br>还有一个稳妥方法就是看文档，比如<a href="https://html.spec.whatwg.org/multipage/webappapis.html#timer-initialisation-steps" target="_blank" rel="noopener">setTimeout</a>是宏任务，<a href="https://dom.spec.whatwg.org/#queue-a-mutation-record" target="_blank" rel="noopener">mutation</a>是微任务。正如上文提到的，ECMAScript 中把微任务叫做jobs，<a href="http://www.ecma-international.org/ecma-262/6.0/#sec-performpromisethen" target="_blank" rel="noopener">EnqueueJob</a>是微任务。</p>
<h2 id="复杂实例"><a href="#复杂实例" class="headerlink" title="复杂实例"></a>复杂实例</h2><h3 id="实例1"><a href="#实例1" class="headerlink" title="实例1"></a>实例1</h3><pre><code>&lt;div class=&quot;outer&quot;&gt;
  &lt;div class=&quot;inner&quot;&gt;&lt;/div&gt;
&lt;/div&gt;
</code></pre><pre><code>// Let&#39;s get hold of those elements
var outer = document.querySelector(&#39;.outer&#39;);
var inner = document.querySelector(&#39;.inner&#39;);

// Let&#39;s listen for attribute changes on the
// outer element
//监听element属性变化
new MutationObserver(function() {
  console.log(&#39;mutate&#39;);
}).observe(outer, {
  attributes: true
});

// Here&#39;s a click listener…
function onClick() {
  console.log(&#39;click&#39;);

  setTimeout(function() {
    console.log(&#39;timeout&#39;);
  }, 0);

  Promise.resolve().then(function() {
    console.log(&#39;promise&#39;);
  });

  outer.setAttribute(&#39;data-random&#39;, Math.random());
}

// …which we&#39;ll attach to both elements
inner.addEventListener(&#39;click&#39;, onClick);
outer.addEventListener(&#39;click&#39;, onClick);
</code></pre><p>结果应该为：</p>
<pre><code>click
promise
mutate
click
promise
mutate
timeout
timeout
</code></pre><p>实际测试结果：</p>
<p><img src="/2019/11/06/js-tasks-microtasks/ex-1.png" alt="ex"></p>
<p>这里分发click event是一个宏任务，Mutation observer和promise都会进入微任务队列，setTimeout回调是一个宏任务。</p>
<p>我之前也不知道只要执行栈中没有js代码在执行，微任务会在回调后立即执行，我之前认为它只会在宏任务结束后执行（Although we are mid-task,microtasks are processed after callbacks if the stack is empty）.这个规则来自于HTML标准中关于回调调用的部分</p>
<blockquote>
<p>If the stack of script settings objects is now empty, perform a microtask checkpoint<br>— HTML: Cleaning up after a callback step 3</p>
</blockquote>
<p>如果<a href="https://html.spec.whatwg.org/multipage/webappapis.html#stack-of-script-settings-objects" target="_blank" rel="noopener">js执行栈</a>空了,立即执行<a href="https://html.spec.whatwg.org/multipage/webappapis.html#perform-a-microtask-checkpoint" target="_blank" rel="noopener">microtask checkpoint</a><br>—— <a href="https://html.spec.whatwg.org/multipage/webappapis.html#clean-up-after-running-a-callback" target="_blank" rel="noopener">HTML: Cleaning up after a callback</a><br>microtask checkpoint 会检查整个微任务队列，除非正在执行这个检查动作。ECMAScript 标准中说到HTML环境下，必须执行。</p>
<blockquote>
<p>Execution of a Job can be initiated only when there is no running execution context and the execution context stack is empty…<br>— ECMAScript: Jobs and Job Queues</p>
</blockquote>
<p>Firefox和Safari在click监听器回调之间正确执行了mutation 回调的微任务，但promise打印结果却出现在了错误的位置。<br>无可厚非的是jobs和微任务的关系太含糊不清，不过我仍认为应该在click监听器回调之间执行。<br>Edge我们早就知道会把promise回调放进错误的队列，但他也也没在click监听器回调之间执行微任务队列，而是在所有监听器回调后执行，这打印click之后只打印了一次mutate，为此我给它提了个bug。</p>
<h3 id="实例二"><a href="#实例二" class="headerlink" title="实例二"></a>实例二</h3><p>代码同实例一，触发事件的方式由点击按钮改为<code>inner.click()</code>。这依旧会开始分发事件，但这次是使用脚本而不是交互点击。</p>
<p>结果应该为：</p>
<pre><code>click
click
promise
mutate
promise
timeout
timeout
</code></pre><p>实际测试结果：</p>
<p><img src="/2019/11/06/js-tasks-microtasks/ex-2.png" alt="ex2"></p>
<p>在每个监听器回调调用之后</p>
<blockquote>
<p>If the stack of script settings objects is now empty, perform a microtask checkpoint<br>— HTML: Cleaning up after a callback step 3</p>
</blockquote>
<p>之前的例子，微任务会在监听器回调之间执行。但这里的例子，<code>click()</code>会导致事件同步分发，所以在监听器回调之间Js执行栈不为空，而上述的这个规则保证了微任务不会打断正在执行的js.这意味着我们不能在监听器回调之间执行微任务，微任务会在监听器之后执行。</p>
<h3 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h3><ul>
<li>宏任务按顺序执行，且浏览器在每个宏任务之间渲染页面</li>
<li>所有微任务也按顺序执行，且在以下场景会立即执行所有微任务<ul>
<li>每个回调之后且js执行栈中为空。</li>
<li>每个宏任务结束后。</li>
</ul>
</li>
</ul>
<blockquote>
<p>【译者注】本文的实例原文中作者都做了逐步执行的demo，其中还加入了执行栈的动画还有讲解，十分清晰</p>
</blockquote>

      
    </div>
    
    
    

    

    

    

    <footer class="post-footer">
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2019/11/04/js-gabage-collect/" rel="next" title="垃圾收集">
                <i class="fa fa-chevron-left"></i> 垃圾收集
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2019/11/07/js-event-loop/" rel="prev" title="js中的事件循环">
                js中的事件循环 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          

  
    <div class="comments" id="comments">
    </div>
  



        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap">
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview-wrap">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview-wrap sidebar-panel">
        <div class="site-overview">
          <div class="site-author motion-element" itemprop="author" itemscope="" itemtype="http://schema.org/Person">
            
              <p class="site-author-name" itemprop="name">renhao</p>
              <p class="site-description motion-element" itemprop="description"></p>
          </div>

          <nav class="site-state motion-element">

            
              <div class="site-state-item site-state-posts">
              
                <a href="/archives/">
              
                  <span class="site-state-item-count">94</span>
                  <span class="site-state-item-name">日志</span>
                </a>
              </div>
            

            
              
              
              <div class="site-state-item site-state-categories">
                <a href="/categories/index.html">
                  <span class="site-state-item-count">19</span>
                  <span class="site-state-item-name">分类</span>
                </a>
              </div>
            

            

          </nav>

          
            <div class="feed-link motion-element">
              <a href="/atom.xml" rel="alternate">
                <i class="fa fa-rss"></i>
                RSS
              </a>
            </div>
          

          

          
          

          
          

          

        </div>
      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#一个简单实例"><span class="nav-number">1.</span> <span class="nav-text">一个简单实例</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#深层原因"><span class="nav-number">2.</span> <span class="nav-text">深层原因</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#宏任务（task）"><span class="nav-number">2.1.</span> <span class="nav-text">宏任务（task）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#微任务（Microtasks）"><span class="nav-number">2.2.</span> <span class="nav-text">微任务（Microtasks）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#不同浏览器打印顺序不一致原因"><span class="nav-number">2.3.</span> <span class="nav-text">不同浏览器打印顺序不一致原因</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#分辨宏任务、微任务"><span class="nav-number">2.4.</span> <span class="nav-text">分辨宏任务、微任务</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#复杂实例"><span class="nav-number">3.</span> <span class="nav-text">复杂实例</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#实例1"><span class="nav-number">3.1.</span> <span class="nav-text">实例1</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#实例二"><span class="nav-number">3.2.</span> <span class="nav-text">实例二</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#总结"><span class="nav-number">3.3.</span> <span class="nav-text">总结</span></a></li></ol></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright">&copy; <span itemprop="copyrightYear">2020</span>
  <span class="with-love">
    <i class="fa fa-user"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">renhao</span>

  
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item-icon">
      <i class="fa fa-area-chart"></i>
    </span>
    
      <span class="post-meta-item-text">Site words total count&#58;</span>
    
    <span title="Site words total count">265.9k</span>
  
</div>


  <div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动</div>



  <span class="post-meta-divider">|</span>



  <div class="theme-info">主题 &mdash; <a class="theme-link" target="_blank" href="https://github.com/iissnan/hexo-theme-next">NexT.Muse</a> v5.1.4</div>




        







        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  
    <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>
  

  
  
    <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>
  

  
  
    <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>
  

  
  
    <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>
  


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.4"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.4"></script>



  
  

  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.4"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.4"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.4"></script>



  


  




	





  





  










  <script src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
  <script src="//unpkg.com/valine/dist/Valine.min.js"></script>
  
  <script type="text/javascript">
    var GUEST = ['nick','mail','link'];
    var guest = 'nick,mail,link';
    guest = guest.split(',').filter(item=>{
      return GUEST.indexOf(item)>-1;
    });
    new Valine({
        el: '#comments' ,
        verify: false,
        notify: false,
        appId: '2P1xqUWiCoNm14MH4yhURlJi-gzGzoHsz',
        appKey: 'uJN0uagHIVgXtBO1OuLV9Ban',
        placeholder: 'Just go go',
        avatar:'mm',
        guest_info:guest,
        pageSize:'10' || 10,
    });
  </script>



  





  

  

  

  
  

  

  

  

</body>
</html>
